package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
import com.dlc.shop.bean.app.dto.DeliveryDto;
import com.dlc.shop.bean.app.dto.OrderRefundInterventionDTO;
import com.dlc.shop.bean.bo.OrderChangeShopWalletAmountBO;
import com.dlc.shop.bean.bo.PayInfoResultBO;
import com.dlc.shop.bean.dto.OrderRefundDto;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.*;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.OrderRefundParam;
import com.dlc.shop.bean.param.UserManagerParam;
import com.dlc.shop.bean.pay.RefundInfoDto;
import com.dlc.shop.bean.vo.OrderRefundInterventionVO;
import com.dlc.shop.bean.vo.SkuStockVO;
import com.dlc.shop.bean.vo.StockPointSkuVO;
import com.dlc.shop.bean.vo.allinpay.SplitRuleVO;
import com.dlc.shop.common.allinpay.constant.PaySysType;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.CacheNames;
import com.dlc.shop.common.constants.PlatformInterventionStatus;
import com.dlc.shop.common.constants.StockPointType;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.dao.OrderRefundInterventionMapper;
import com.dlc.shop.dao.OrderRefundMapper;
import com.dlc.shop.manager.impl.AllinpayOrderManager;
import com.dlc.shop.manager.impl.StockManager;
import com.dlc.shop.service.*;
import com.dlc.shop.util.StockUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yami
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderRefundServiceImpl extends ServiceImpl<OrderRefundMapper, OrderRefund> implements OrderRefundService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final OrderRefundMapper orderRefundMapper;
    private final OrderService orderService;
    private final NotifyTemplateService notifyTemplateService;
    private final ShopWalletService shopWalletService;
    private final SkuService skuService;
    private final SkuStockService skuStockService;
    private final StockManager stockManager;
    private final OrderItemService orderItemService;
    private final RefundOrderSettlementService refundOrderSettlementService;
    private final RefundDeliveryService refundDeliveryService;
    private final OrderSettlementService orderSettlementService;
    private final StockBillLogService stockBillLogService;
    private final RefundAddrService refundAddrService;
    private final ApplicationContext applicationContext;
    private final DeliveryService deliveryService;
    private final OrderInvoiceService orderInvoiceService;
    private final ApplicationEventPublisher eventPublisher;
    private final RefundInfoService refundInfoService;
    private final PayInfoService payInfoService;
    private final OrderVirtualInfoService orderVirtualInfoService;
    private final AllinpayOrderManager allinpayOrderManager;
    private final OrderRefundInterventionMapper orderRefundInterventionMapper;
    private final UserService userService;
    private final ShopDetailService shopDetailService;


    /**
     * 获取分页对象
     */
    @Override
    public IPage<OrderRefundDto> getPage(Page page, OrderRefundDto orderRefundDto, String startTime, String endTime, Integer type) {
        IPage<OrderRefundDto> orderRefundDtoIpage = orderRefundMapper.getPage(page, orderRefundDto, startTime, endTime);
        List<OrderRefundDto> records = orderRefundDtoIpage.getRecords();
        for (OrderRefundDto record : records) {
            getReasonType(record);
            getRefundTypeByOrderItem(record, type);
            if (Objects.nonNull(record.getApplyInterventionTime())) {
                record.setPlatformProcessingEndTime(DateUtil.offsetDay(record.getApplyInterventionTime(), 7));
            }
            if (Objects.nonNull(record.getBuyerMobile())) {
                record.setBuyerMobile(PhoneUtil.hideBetween(record.getBuyerMobile()).toString());
            }
        }
        return orderRefundDtoIpage;
    }

    /**
     * 对退款原因进行国际化
     *
     * @param record
     */
    private void getReasonType(OrderRefundDto record) {
        try {
            BuyerReasonType reasonType = BuyerReasonType.instance(Integer.valueOf(record.getBuyerReason()));
            if (Objects.nonNull(reasonType)) {
                record.setBuyerReason(I18nMessage.getDbLang() == 0 ? reasonType.getCn() : reasonType.getEn());
                if (reasonType.value().equals(BuyerReasonType.GROUP_FAILED.value())) {
                    // 当退款原因为拼团失败时，退款说明与卖家备注进行国际化
                    record.setBuyerDesc(I18nMessage.getDbLang() == 0 ? reasonType.getCn() : reasonType.getEn());
                    record.setSellerMsg(I18nMessage.getDbLang() == 0 ? reasonType.getCn() : reasonType.getEn());
                }
            }
        } catch (NumberFormatException ignored) {
            //如果出现BuyerReasonType没有的类型，则默认即可
        }
    }

    /**
     * 根据编码查询退款单信息
     *
     * @param refundSn 退款单编码
     * @return 退款包装对象
     */
    @Override
    public OrderRefundDto getOrderRefundByRefundSn(String refundSn) {
        OrderRefundDto orderRefundDto = orderRefundMapper.getOrderRefundByRefundSn(refundSn);
        if (orderRefundDto == null) {
            return null;
        }
        // 如果是单项退款,且订单状态为待发货，则退款数量为：主商品数量+赠品数量
        if (orderRefundDto.getRefundType().equals(RefundType.SINGLE.value()) && orderRefundDto.getStatus().equals(OrderStatus.PADYED.value())) {
            Integer prodNum = orderItemService.getOrderItemProdNum(orderRefundDto.getOrderItemId());
            orderRefundDto.setGoodsNum(prodNum);
        }
        // 如果是整单退款,判断一下能否进行平台介入,如果有其他正在进行的就不能进行
        List<OrderRefund> processingOrderRefunds = orderRefundMapper.getProcessingOrderRefundByOrderId(orderRefundDto.getOrderId());
        if(Objects.equals(orderRefundDto.getRefundType(),RefundType.ALL.value())) {
            orderRefundDto.setCanApplyRefund(CollectionUtil.isEmpty(processingOrderRefunds));
        } else {
            List<OrderRefund> filterOrderRefunds = processingOrderRefunds.stream().filter(orderRefund ->
                    Objects.equals(orderRefund.getOrderItemId(), 0L) || Objects.equals(orderRefund.getOrderItemId(), orderRefundDto.getOrderItemId())).toList();
            orderRefundDto.setCanApplyRefund(CollectionUtil.isEmpty(filterOrderRefunds));
        }
        //获取总数，如果为0则为全部
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderRefundDto.getOrderNumber()));
        if (orderRefundDto.getGoodsNum() == 0) {
            orderRefundDto.setGoodsNum(order.getProductNums());
        }
        orderRefundDto.setOrderMold(order.getOrderMold());
        // 判断退款单类型（1:整单退款,2:单个物品退款）
        getRefundTypeByOrderItem(orderRefundDto, 1);
        orderRefundDto.setIsCancel(true);
        // 目前运费不在提交时计算,所以都可以撤销
        // 查询平台介入信息
        handleIntervention(orderRefundDto);
        return orderRefundDto;
    }

    private void handleIntervention(OrderRefundDto orderRefundDto) {
        if(Objects.nonNull(orderRefundDto.getApplyInterventionTime())){
            orderRefundDto.setInterventionEndTime(DateUtil.offsetHour(orderRefundDto.getApplyInterventionTime(),72));
            orderRefundDto.setPlatformProcessingEndTime(DateUtil.offsetDay(orderRefundDto.getApplyInterventionTime(), 7));
        }
        List<OrderRefundInterventionVO> orderRefundInterventionList = orderRefundInterventionMapper.listByRefundId(orderRefundDto.getRefundId());
        // 处理一下名称？还是直接在保存时存入名称？还是处理名称比较好
        Map<Integer, List<OrderRefundInterventionVO>> refundInterventionMap = orderRefundInterventionList.stream()
                .collect(Collectors.groupingBy(OrderRefundInterventionVO::getSysType));
        String userNickName = "";
        if(CollectionUtil.isNotEmpty(refundInterventionMap.get(SysTypeEnum.ORDINARY.value()))) {
            User user = userService.getUserByUserId(refundInterventionMap.get(SysTypeEnum.ORDINARY.value()).get(0).getBizId().toString());
            userNickName = Objects.isNull(user) ? "用户已注销" : user.getNickName();
        }
        String shopName = "";
        if(CollectionUtil.isNotEmpty(refundInterventionMap.get(SysTypeEnum.MULTISHOP.value()))) {
            ShopDetail shopDetail = shopDetailService.getById(refundInterventionMap.get(SysTypeEnum.MULTISHOP.value()).get(0).getBizId());
            shopName = Objects.isNull(shopDetail) ? "" : shopDetail.getShopName();
        }

        for (OrderRefundInterventionVO  orderRefundIntervention : orderRefundInterventionList) {
            switch (orderRefundIntervention.getSysType()){
                case 0:
                    orderRefundIntervention.setBizName(userNickName);
                    break;
                case 1:
                    orderRefundIntervention.setBizName(shopName);
                    break;

                default:
                    break;
            }
        }
        orderRefundDto.setOrderRefundInterventionList(orderRefundInterventionList);
    }

    /**
     * 根据退款ID获取退款单信息
     *
     * @param refundId 退款单ID
     * @return
     */
    @Override
    public OrderRefundDto getOrderRefundById(Long refundId, Long shopId) {
        OrderRefundDto orderRefundDto = orderRefundMapper.getById(refundId, shopId);
        if (orderRefundDto == null) {
            // 无法获取退款订单信息
            throw new YamiShopBindException("yami.unable.refund.information");
        }
        // 如果是整单退款,判断一下能否进行平台介入,如果有其他正在进行的就不能进行
        List<OrderRefund> processingOrderRefunds = orderRefundMapper.getProcessingOrderRefundByOrderId(orderRefundDto.getOrderId());
        if(Objects.equals(orderRefundDto.getRefundType(),RefundType.ALL.value())){
            orderRefundDto.setCanApplyRefund(CollectionUtil.isEmpty(processingOrderRefunds));
        }else {
            List<OrderRefund> filterOrderRefunds = processingOrderRefunds.stream().filter(orderRefund ->
                    Objects.equals(orderRefund.getOrderItemId(), 0L) || Objects.equals(orderRefund.getOrderItemId(), orderRefundDto.getOrderItemId())).toList();
            orderRefundDto.setCanApplyRefund(CollectionUtil.isEmpty(filterOrderRefunds));
        }
        // 判断退款单类型（1:整单退款,2:单个物品退款）
        getRefundTypeByOrderItem(orderRefundDto, RefundType.ALL.value());
        getReasonType(orderRefundDto);
        if (Objects.equals(orderRefundDto.getApplyType(), RefundApplyType.RETURN_REFUND.value())) {
            orderRefundDto.setDeliveryDto(getDeliverInfoByRefundSn(orderRefundDto.getRefundSn()));
        }

        // 查询平台介入信息
        handleIntervention(orderRefundDto);
        return orderRefundDto;
    }

    @Override
    public OrderRefund getOrderRefundByRefundSn(String refundSn, Long shopId) {
        OrderRefund orderRefund = orderRefundMapper.selectOne(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getRefundSn, refundSn)
                .eq(OrderRefund::getShopId, shopId)
        );
        if (Objects.isNull(orderRefund)) {
            // 无法获取退款订单信息
            throw new YamiShopBindException("yami.unable.refund.information");
        }
        return orderRefund;
    }

    @Override
    public DeliveryDto getDeliverInfoByRefundSn(String refundSn) {
        RefundDelivery refundDelivery = refundDeliveryService.getOne(new LambdaQueryWrapper<RefundDelivery>()
                .eq(RefundDelivery::getRefundSn, refundSn));
        DeliveryDto deliveryDto = null;
        if (Objects.nonNull(refundDelivery) && Objects.nonNull(refundDelivery.getDeyId())) {
            try {
                Delivery delivery = deliveryService.getById(refundDelivery.getDeyId());
                deliveryDto = deliveryService.query(delivery, refundDelivery.getDeyNu(), refundDelivery.getReceiverMobile());
                if(Objects.nonNull(deliveryDto)){
                    deliveryDto.setCompanyName(refundDelivery.getDeyName());
                    deliveryDto.setDvyFlowId(refundDelivery.getDeyNu());
                }
            } catch (Exception e) {
                log.error("物流查询错误：", e);
                // 查询出错
                throw new YamiShopBindException("yami.query.error");
            }
        }
        return deliveryDto;
    }

    /**
     * 生成退款单
     *
     * @param orderRefund 退款对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyRefund(OrderRefund orderRefund) {
        // 生成退款单
        save(orderRefund);
        // 更新订单状态
        Order order = orderService.getById(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.APPLY.value());
        orderService.updateById(order);

        // 消息推送-申请退款
        notifyTemplateService.sendNotifyOfApplyRefund(order, orderRefund);
    }


    /**
     * 判断退款单类型（1:整单退款,2:单个物品退款）
     * sysType,1.展示赠品信息，0.不展示
     */
    private void getRefundTypeByOrderItem(OrderRefundDto orderRefundDto, Integer sysType) {
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderId, orderRefundDto.getOrderId()).eq(Order::getShopId, orderRefundDto.getShopId()));
        orderRefundDto.setPlatformAmount(Arith.sub(order.getPlatformAmount(),order.getPlatformFreeFreightAmount()));
        orderRefundDto.setPlatformFreeFreightAmount(order.getPlatformFreeFreightAmount());
        List<OrderItem> orderItems = orderItemService.list(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, orderRefundDto.getOrderNumber()));
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            orderRefundDto.setRefundScore(orderItems.stream().mapToLong(OrderItem::getUseScore).sum());
            //放入赠品信息
            if (Objects.equals(sysType, 1)) {
                orderItemService.handleActivityOrderItem(orderItems,null);
            }
            orderRefundDto.setOrderItems(orderItems);
        } else {
            orderRefundDto.setFreightAmount(order.getFreightAmount());
            OrderItem item = orderItems.stream().filter(orderItem ->  Objects.equals(orderItem.getOrderItemId(),orderRefundDto.getOrderItemId())).toList().get(0);
            item.setProdCount(orderRefundDto.getGoodsNum());
            orderRefundDto.getOrderItems().add(item);

            orderRefundDto.setRefundScore(item.getUseScore());
            if (Objects.equals(sysType, 0)) {
                return;
            }
            // 处理一下赠品和组合商品子订单项
            Map<Long, List<OrderItem>> comboMap = orderItems.stream()
                    .filter(s -> Objects.equals(s.getActivityType(), OrderActivityType.COMBO_PROD.value()))
                    .collect(Collectors.groupingBy(OrderItem::getActivityId));
            item.setComboList(comboMap.get(item.getOrderItemId()));

            if(Objects.isNull(orderRefundDto.getReturnGiveawayIds())) {
                return;
            }
            List<String> itemIds = Arrays.asList(orderRefundDto.getReturnGiveawayIds().split(StrUtil.COMMA));
            List<OrderItem> giveawayOrderItems = new ArrayList<>();
            Map<Long, List<OrderItem>> giveawawMap = orderItems.stream()
                    .filter(s -> Objects.equals(s.getActivityType(), OrderActivityType.GIVEAWAY.value()))
                    .collect(Collectors.groupingBy(OrderItem::getActivityId));
            for (OrderItem orderItem : giveawawMap.get(item.getOrderItemId())) {
                if (!itemIds.contains(orderItem.getOrderItemId().toString())) {
                    continue;
                }
                giveawayOrderItems.add(orderItem);
            }
            item.setGiveawayList(giveawayOrderItems);
        }
    }

    /**
     * 卖家处理（退款/返回退货地址）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderRefundDto processRefundOrder(OrderRefundParam orderRefundParam, Long shopId) {
        RefundDelivery dbDelivery = refundDeliveryService.getOne(new LambdaQueryWrapper<RefundDelivery>()
                .eq(RefundDelivery::getRefundSn, orderRefundParam.getRefundSn()));
        if (Objects.nonNull(dbDelivery) & !orderRefundParam.getIsPaltform()) {
            logger.info("重复提交退货地址判断");
            throw new YamiShopBindException("yami.prod.common.invalid");
        }
        OrderRefundDto orderRefundDto = getOrderRefundById(orderRefundParam.getRefundId(), shopId);
        if (Objects.nonNull(orderRefundParam.getRefundAmount())) {
            logger.info("平台处理介入退款金额");
            orderRefundDto.setRefundAmount(orderRefundParam.getRefundAmount());
        }
        if (Objects.equals(-1, orderRefundDto.getReturnMoneySts()) & !orderRefundParam.getIsPaltform()) {
            // 买家已取消申请
            throw new YamiShopBindException("yami.order.refund.cancel");
        }
        Date now = new Date();


        // 是否同意退款
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            // 不同意退款
            disagreeRefund(orderRefundParam, orderRefundDto);
        } else {
            // 正在处理退款的状态(不是平台处理介入退款时)
            if (!orderRefundParam.getIsPaltform()) {
                orderRefundDto.setReturnMoneySts(ReturnMoneyStsType.PROCESSING.value());
            }

            // 判断是退款退货/仅退款(1:仅退款 2:退款退货)
            if (Objects.equals(orderRefundDto.getApplyType(), 1)) {
                // 同意退款
                checkLastRefund(orderRefundDto);
                agreeRefund(orderRefundDto);
                // 减少商家结算金额
                subShopSettlementAmount(orderRefundDto);
            } else {
                // 同意退款退货操作
                // 设置退货物流信息
                RefundAddr refundAddr = refundAddrService.getById(orderRefundParam.getRefundAddrId());
                if (refundAddr == null) {
                    // 请设置退货物流信息
                    throw new YamiShopBindException("yami.set.refund.information");
                }
                if (!orderRefundParam.getIsPaltform()) {
                    logger.info("不是平台介入处理退款");
                    RefundDelivery refundDelivery = new RefundDelivery();
                    refundDelivery.setShopId(orderRefundDto.getShopId());
                    refundDelivery.setRefundSn(orderRefundDto.getRefundSn());
                    refundDelivery.setUserId(orderRefundDto.getUserId());
                    refundDelivery.setReceiverName(refundAddr.getReceiverName());
                    refundDelivery.setReceiverMobile(refundAddr.getReceiverMobile());
                    refundDelivery.setReceiverTelephone(refundAddr.getReceiverTelephone());
                    refundDelivery.setReceiverPostCode(refundAddr.getPostCode());
                    String addr = refundAddr.getProvince() + refundAddr.getCity() + refundAddr.getArea() + refundAddr.getAddr();
                    refundDelivery.setReceiverAddr(addr);
                    refundDelivery.setCreateTime(new Date());
                    refundDeliveryService.save(refundDelivery);
                }
                // 消息推送-同意退款
                notifyTemplateService.sendNotifyByRefund(orderRefundDto, SendType.AGREE_REFUND);
            }

        }

        // 设置卖家备注
        orderRefundDto.setSellerMsg(orderRefundParam.getSellerMsg());
        // 受理时间
        orderRefundDto.setHandelTime(now);
        // 更新时间
        orderRefundDto.setUpdateTime(now);
        orderRefundDto.setBuyerReason(null);
        // 更新数据
        updateById(orderRefundDto);
        return orderRefundDto;
    }

    /**
     * 收到货同意退款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderRefundDto returnMoney(OrderRefundParam orderRefundParam, Long shopId) {
        // 获取退款单信息
        OrderRefundDto orderRefundDto = getOrderRefundById(orderRefundParam.getRefundId(), shopId);

        if (!Objects.equals(ReturnMoneyStsType.CONSIGNMENT.value(), orderRefundDto.getReturnMoneySts()) & !orderRefundParam.getIsPaltform()) {
            // 订单状态已经发生改变，请勿重复操作
            throw new YamiShopBindException("yami.order.status.change");
        }
        if (Objects.equals(-1, orderRefundDto.getReturnMoneySts()) & !orderRefundParam.getIsPaltform()) {
            // 买家已取消申请
            throw new YamiShopBindException("yami.order.refund.cancel");
        }
        Date now = new Date();
        if (Objects.nonNull(orderRefundParam.getRefundAmount())) {
            logger.info("平台处理介入设置退款金额");
            orderRefundDto.setRefundAmount(orderRefundParam.getRefundAmount());
        }
        // 是否同意退款
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.AGREE.value())) {
            // 减少商家结算金额
            subShopSettlementAmount(orderRefundDto);

            // 同意操作(不是平台处理介入退款时)
            if (!orderRefundParam.getIsPaltform()) {
                orderRefundDto.setReturnMoneySts(ReturnMoneyStsType.RECEIVE.value());
            }
            // 同意退款
            agreeRefund(orderRefundDto);

        } else {
            disagreeRefund(orderRefundParam, orderRefundDto);
        }

        // 是否收到货
        orderRefundDto.setIsReceiver(orderRefundParam.getIsReceiver());

        // 收货时间(收到商品才更新)
        if (orderRefundDto.getIsReceiver()) {
            orderRefundDto.setReceiveTime(now);
        }

        // 更新时间
        orderRefundDto.setUpdateTime(now);
        orderRefundDto.setBuyerReason(null);
        // 更新数据
        updateById(orderRefundDto);

        return orderRefundDto;
    }

    /**
     * 减少商家结算金额/未结算金额
     */
    private void subShopSettlementAmount(OrderRefundDto orderRefundDto) {
        Long shopId = orderRefundDto.getShopId();
        // 同意退款，判断商家是否还有金额进行退款
        Order order = orderService.getOrderByOrderNumber(orderRefundDto.getOrderNumber());
        if (order == null) {
            // 未找到该订单信息
            throw new YamiShopBindException("yami.no.found.order");
        }

        // 实付金额
        double actualTotal;
        //商家供应价格
        double supplierTotal;
        double platformCommission;
        double changePlatformCommission;
        Double rate = 0.0;
        double distributionAmount;
        double shopAmount;
        double platformFreeFreightAmount = 0.0;
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            //整单退款
            actualTotal = order.getActualTotal();
            supplierTotal = order.getSupplierTotal();
            platformCommission = order.getPlatformCommission();
            distributionAmount = order.getDistributionAmount();
            shopAmount = Arith.sub(order.getReduceAmount(),order.getPlatformAmount());
            // 如果是已经发货的整单订单,还需要加上平台包邮金额
            if (Objects.equals(order.getStatus(), OrderStatus.CONSIGNMENT.value()) || Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value())) {
                platformFreeFreightAmount = order.getPlatformFreeFreightAmount();
            }
        } else {
            //单件物品退款
            OrderItem item = orderItemService.getByOrderItemId(orderRefundDto.getOrderItemId());
            actualTotal = item.getActualTotal();
            supplierTotal = item.getSupplierPrice();
            // 平台佣金
            platformCommission = item.getPlatformCommission();
            rate = item.getRate();
            // 分销金额 = 直推分销金额 + 间推分销金额
            distributionAmount = item.getDistributionAmount() + item.getDistributionParentAmount();
            shopAmount = Arith.sub(item.getShareReduce(),item.getPlatformShareReduce());
        }


        OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO = new OrderChangeShopWalletAmountBO();
        orderChangeShopWalletAmountBO.setOrderStatus(order.getStatus());
        orderChangeShopWalletAmountBO.setPlatformFreeFreightAmount(platformFreeFreightAmount);
        orderChangeShopWalletAmountBO.setActualTotal(actualTotal);
        orderChangeShopWalletAmountBO.setRefundAmount(orderRefundDto.getRefundAmount());
        orderChangeShopWalletAmountBO.setSupplierTotal(supplierTotal);
        orderChangeShopWalletAmountBO.setPlatformAllowanceAmount(orderRefundDto.getPlatformRefundAmount());
        orderChangeShopWalletAmountBO.setOrderNumber(order.getOrderNumber());
        orderChangeShopWalletAmountBO.setRefundSn(orderRefundDto.getRefundSn());
        orderChangeShopWalletAmountBO.setShopId(orderRefundDto.getShopId());
        orderChangeShopWalletAmountBO.setOrderItemId(orderRefundDto.getOrderItemId());
        orderChangeShopWalletAmountBO.setPlatformCommission(platformCommission);
        orderChangeShopWalletAmountBO.setChangePlatformCommission(orderRefundDto.getPlatformRefundCommission());
        orderChangeShopWalletAmountBO.setShopReduceAmount(shopAmount);
        orderChangeShopWalletAmountBO.setRate(rate);
        orderChangeShopWalletAmountBO.setDistributionAmount(distributionAmount);
        orderChangeShopWalletAmountBO.setPaySysType(order.getPaySysType());
        shopWalletService.refundShopAmountByRefund(orderChangeShopWalletAmountBO);
    }

    /**
     * 不同意退款
     */
    private void disagreeRefund(OrderRefundParam orderRefundParam, OrderRefundDto orderRefundDto) {
        // 不同意退款
        orderRefundDto.setReturnMoneySts(ReturnMoneyStsType.FAIL.value());
        // 拒绝原因
        orderRefundDto.setRejectMessage(orderRefundParam.getRejectMessage());
        orderRefundDto.setRejectTime(new Date());

        // 更新订单
        Order order = orderService.getById(orderRefundDto.getOrderId());
        Long orderRefundSuccessCount = orderRefundMapper.selectCount(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderRefundDto.getOrderId())
                .eq(OrderRefund::getReturnMoneySts, ReturnMoneyStsType.SUCCESS.value()));
        orderRefundMapper.update(null, new LambdaUpdateWrapper<OrderRefund>()
                .eq(OrderRefund::getRefundId, orderRefundParam.getRefundId())
                .set(OrderRefund::getShopImgUrls, orderRefundParam.getShopImgUrls()));
        // 如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
        if (orderRefundSuccessCount > 0) {
            order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
        } else {
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
        }
        orderService.updateById(order);

        // 消息推送--拒绝退款
        notifyTemplateService.sendNotifyByRefund(orderRefundDto, SendType.REFUSE_REFUND);
    }

    /**
     * 买家提交物流信息
     * @param orderRefund    退款单对象
     * @param refundDelivery 退款物流单对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitExpress(OrderRefund orderRefund, RefundDelivery refundDelivery) {
        refundDeliveryService.updateById(refundDelivery);
        updateById(orderRefund);

        // 消息推送-用户已退货
        Order order = orderService.getById(orderRefund.getOrderId());
        order.setRemarks(refundDelivery.getSenderRemarks());
        notifyTemplateService.sendNotifyByUserRefundDelivery(order, SendType.RETURN_REFUND);
    }

    /**
     * 系统自动退款操作（批量）
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void systemAutoRefundBatch(List<OrderRefundDto> orderRefundDtoList) {
        for (OrderRefundDto orderRefundDto : orderRefundDtoList) {
            agreeRefund(orderRefundDto);
            update(orderRefundDto, new LambdaQueryWrapper<OrderRefund>()
                    .eq(OrderRefund::getRefundSn, orderRefundDto.getRefundSn()));
            // 减少商家未结算金额
            subShopSettlementAmount(orderRefundDto);

            try {
                submitWxRefund(orderRefundDto);
            } catch (YamiShopBindException e) {
                WxPayException wxPayException = (WxPayException) e.getObject();
                if (Objects.equals("订单已全额退款", wxPayException.getErrCodeDes())) {
                    continue;
                }
                throw e;
            }
        }
    }

    /**
     * 系统验证退款结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void verifyRefund(RefundInfo refundInfo, String payRefundId) {
        // 查询退款结算记录
        RefundOrderSettlement refundOrderSettlement = refundOrderSettlementService.getOne(
                new LambdaQueryWrapper<RefundOrderSettlement>().eq(RefundOrderSettlement::getRefundSn, refundInfo.getRefundId()));
        // 判断退款结算记录是否为申请状态
        if (refundOrderSettlement == null || refundOrderSettlement.getRefundStatus() != 1) {
            // 退款已处理，无需重复处理
            throw new YamiShopBindException("yami.refund.processed");
        }
        // 更新退款结算记录
        boolean update = refundOrderSettlementService.update(new LambdaUpdateWrapper<RefundOrderSettlement>()
                .set(RefundOrderSettlement::getRefundStatus, RefundStatusEnum.SUCCEED.value())
                .set(RefundOrderSettlement::getPayRefundId, payRefundId)
                .eq(RefundOrderSettlement::getRefundStatus, RefundStatusEnum.APPLY.value())
                .eq(RefundOrderSettlement::getSettlementId, refundOrderSettlement.getSettlementId()));
        if (!update) {
            throw new YamiShopBindException("yami.refund.processed");
        }
        // 更新订单
        Order order = orderService.getOrderByOrderNumber(refundInfo.getOrderNumber());
        int oldOrderStatus = order.getStatus();

        OrderRefundDto orderRefundDto = getOrderRefundByRefundSn(refundInfo.getRefundId());
        // 退款成功（保存退款结算记录、更新订单、还原库存）
        refundSuccess(order, orderRefundDto, refundInfo);

        // 推送退款成功事件
        applicationContext.publishEvent(new OrderRefundSuccessEvent(orderRefundDto));
        if (Objects.equals(oldOrderStatus, OrderStatus.SUCCESS.value()) && Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            // 还原成长值
            applicationContext.publishEvent(new RefundGrowthEvent(order.getOrderNumber()));
        }

        // 可以退款的状态 && 现在订单关闭了 && 因为退款导致订单关闭
        // 如果订单因为退款关闭，要进行结算给商家的操作，这个结算的计算是退款完成后结算的，所以不要随便改变顺序
        boolean canRefundFlag = Objects.equals(oldOrderStatus, OrderStatus.PADYED.value())
                || Objects.equals(oldOrderStatus, OrderStatus.CONSIGNMENT.value())
                || Objects.equals(oldOrderStatus, OrderStatus.SUCCESS.value());
        if (canRefundFlag && Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())
                && Objects.equals(order.getCloseType(), OrderCloseType.REFUND.value())) {
            handlePartialRefund(order,oldOrderStatus,false);
        }
    }

    /**
     * 处理下部分退款完成，订单关闭的时候未结算变成已结算的金额处理，退款超时定时任务。
     *
     * @param order          订单信息
     * @param oldOrderStatus
     */
    private void handlePartialRefund(Order order, int oldOrderStatus, Boolean isBack) {
        // 1.获取到部分退款并且订单关闭后，需要结算给商家、平台的钱
        // 获取所有正在进行中的退款订单
        List<OrderRefund> orderRefunds = getProcessingOrderRefundByOrderId(order.getOrderId());
        double alreadyRefundAmount = 0.0;
        double changePlatformCommission = 0.0;
        double platformAllowanceAmount = 0.0;
        double distributionAmount = 0.0;
        double platformFreeFreightAmount = 0.0;
        for (OrderRefund orderRefund : orderRefunds) {
            alreadyRefundAmount = Arith.add(alreadyRefundAmount, orderRefund.getRefundAmount());
            changePlatformCommission = Arith.add(changePlatformCommission, orderRefund.getPlatformRefundCommission());
            platformAllowanceAmount = Arith.add(platformAllowanceAmount, orderRefund.getPlatformRefundAmount());
            distributionAmount = Arith.add(distributionAmount, orderRefund.getDistributionTotalAmount());
        }
        if (Objects.equals(oldOrderStatus, OrderStatus.CONSIGNMENT.value()) || Objects.equals(oldOrderStatus, OrderStatus.SUCCESS.value())) {
           platformFreeFreightAmount = order.getPlatformFreeFreightAmount();
        }
        // 如果是已经发货订单的退款,还需要加上平台包邮金额判断
        double partialRefundAmount = Arith.add(Arith.sub(order.getActualTotal(), alreadyRefundAmount),platformFreeFreightAmount);
        if (partialRefundAmount <= 0) {
            return;
        }
        OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO = new OrderChangeShopWalletAmountBO();
        orderChangeShopWalletAmountBO.setOrderStatus(order.getStatus());
        orderChangeShopWalletAmountBO.setActualTotal(order.getActualTotal());
        orderChangeShopWalletAmountBO.setRefundAmount(alreadyRefundAmount);
        orderChangeShopWalletAmountBO.setOrderNumber(order.getOrderNumber());
        orderChangeShopWalletAmountBO.setShopId(order.getShopId());
        orderChangeShopWalletAmountBO.setPlatformCommission(order.getPlatformCommission());

        // 因为整单退款会把平台包邮的金额放入退款表的平台退款金额里面,且在订单已发货时需要支付运费给商家,
        // 所以还需要加上平台包邮金额计算,不然就会导致平台优惠为0,商家少收入一笔平台包邮的运费
        orderChangeShopWalletAmountBO.setPlatformAllowanceAmount(Arith.sub(order.getPlatformAmount(), platformAllowanceAmount));
        orderChangeShopWalletAmountBO.setPlatformFreeFreightAmount(0.0);
        if (Objects.equals(orderRefunds.get(0).getRefundType(),RefundType.ALL.value())){
            orderChangeShopWalletAmountBO.setPlatformFreeFreightAmount(platformFreeFreightAmount);
        }


        orderChangeShopWalletAmountBO.setShopReduceAmount(Arith.sub(order.getReduceAmount(),order.getPlatformAmount()));
        orderChangeShopWalletAmountBO.setChangePlatformCommission(changePlatformCommission);
        orderChangeShopWalletAmountBO.setDistributionAmount(Arith.sub(order.getDistributionAmount(), distributionAmount));
        // 判断一下是否为通联支付，通联支付还需先结算在进行之后操作,如果是回调直接跳过
        if(Objects.equals(order.getPaySysType(), PaySysType.ALLINPAY.value()) && !isBack){
            //    平台结算金额 = 平台佣金改变量 - 平台补贴改变量
            double settlementAmount = orderChangeShopWalletAmountBO.getActualTotal() - orderChangeShopWalletAmountBO.getRefundAmount();
            // 平台补贴改变量
            double changePlatformAmount = orderChangeShopWalletAmountBO.getPlatformAllowanceAmount();
            // 平台佣金改变量
            double changePlatformCommissionAmount = Arith.sub(orderChangeShopWalletAmountBO.getPlatformCommission(), orderChangeShopWalletAmountBO.getChangePlatformCommission());
            // 商家结算金额 =  当前需要结算金额 + 平台补贴改变量 - 平台佣金改变量
            double shopSettlementAmount = Arith.sub(Arith.add(settlementAmount, changePlatformAmount), changePlatformCommissionAmount);
            // 平台结算金额实际上改变金额 = 平台佣金改变量 - 平台补贴改变量
            double platformChangeAmount = Arith.sub(changePlatformCommissionAmount, changePlatformAmount);

            SplitRuleVO shopSplitRuleDto = new SplitRuleVO();
            shopSplitRuleDto.setBizUserId(String.valueOf(order.getShopId()));
            shopSplitRuleDto.setAmount(Arith.toLongCent(shopSettlementAmount));
            shopSplitRuleDto.setFee(Arith.toLongCent(platformChangeAmount));
            allinpayOrderManager.doAllinPaySettlementByRefund(shopSplitRuleDto,order.getOrderNumber());
            return;
        }
        // 订单结算状态改为已结算
        Order newOrder = new Order();
        newOrder.setOrderId(order.getOrderId());
        newOrder.setIsSettled(1);
        orderService.updateById(newOrder);

        // 2.发送消息给商家，将需要结算的钱进行结算
        // 减少商家待结算金额
        applicationContext.publishEvent(new RefundSuccessSettlementEvent(order, orderChangeShopWalletAmountBO));

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponseEntity<String> settlementAllinpayOrderByRefund(PayInfoResultBO payInfoResultBO, PayInfo payInfo) {
        Order order = orderService.getOrderAndOrderItemByOrderNumber(payInfo.getOrderNumbers());
        if (Objects.isNull(order)) {
            return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
        }
        handlePartialRefund(order, order.getStatus(), true);
        return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyPlatormIntervertion(OrderRefundInterventionDTO orderRefundInterventionDTO, OrderRefund orderRefund) {
        // 更新订单状态
        Order order = new Order();
        order.setOrderId(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.APPLY.value());
        orderService.updateById(order);

        // 修改退款信息
        orderRefund.setRefundId(orderRefundInterventionDTO.getRefundId());
        orderRefund.setPlatformInterventionStatus(PlatformInterventionStatus.APPLY.value());
        orderRefund.setApplyInterventionTime(new Date());
        // 保存用户申请平台介入信息
        orderRefund.setApplyInterventionReason(orderRefundInterventionDTO.getVoucherDesc());
        orderRefund.setApplyInterventionImgUrls(orderRefundInterventionDTO.getImgUrls());
        orderRefundMapper.updateById(orderRefund);
        orderRefundInterventionMapper.deleteById(orderRefundInterventionDTO.getRefundId());
        // 设置订单项里的平台介入状态
        updateItemPlatformIntervertion(orderRefund, orderRefundInterventionDTO.getOrderNumber(),PlatformInterventionStatus.APPLY.value());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cacelPlatormIntervertion(OrderRefundInterventionDTO orderRefundInterventionDTO, OrderRefund orderRefund) {
        // 修改退款信息
        orderRefund.setRefundId(orderRefundInterventionDTO.getRefundId());
        orderRefund.setPlatformInterventionStatus(PlatformInterventionStatus.NONE.value());
        orderRefund.setInterventionFinishTime(new Date());
        orderRefund.setReturnMoneySts(ReturnMoneyStsType.FAIL.value());
        // 保存用户申请平台介入信息
        orderRefundMapper.updateById(orderRefund);
        // 更新订单状态
        Integer orderRefundSuccessCount = orderRefundMapper.countReturnProcessingItemByOrderId(orderRefund.getOrderId());
        // 删除平台介入退款凭证信息
        orderRefundInterventionMapper.delete(new LambdaUpdateWrapper<OrderRefundIntervention>()
                .eq(OrderRefundIntervention::getRefundId, orderRefundInterventionDTO.getRefundId()));

        // 更新订单
        // 如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
        Order order = new Order();
        order.setOrderId(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
        if (Objects.equals(orderRefundSuccessCount, 0)) {
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
        }
        orderService.updateById(order);
        // 设置订单项里的平台介入状态
        updateItemPlatformIntervertion(orderRefund, orderRefundInterventionDTO.getOrderNumber(),PlatformInterventionStatus.NONE.value());
    }


    /**
     *  更新订单项平台介入状态
     * @param orderRefund
     * @param orderNumber
     */
    private void updateItemPlatformIntervertion(OrderRefund orderRefund, String orderNumber, Integer ststus) {
        List<OrderItem> orderItemList = new ArrayList<>();
        OrderItem orderItem = null;
        if (Objects.equals(orderRefund.getRefundType(), RefundType.ALL.value())) {
            logger.info("整单退款，设置订单项平台介入退款状态");
            List<Long> orderItemIdList = orderItemService.list(new LambdaQueryWrapper<OrderItem>()
                            .eq(OrderItem::getOrderNumber, orderNumber))
                    .stream().map(OrderItem::getOrderItemId).collect(Collectors.toList());
            for (Long orderItemId : orderItemIdList) {
                orderItem = new OrderItem();
                orderItem.setOrderItemId(orderItemId);
                orderItem.setPlatformInterventionStatus(ststus);
                orderItemList.add(orderItem);
            }
        }
        List<OrderItem> giveawayItemList = new ArrayList<>();
        if (Objects.equals(orderRefund.getRefundType(), RefundType.SINGLE.value())) {
            logger.info("单项退款，设置订单项平台介入退款状态");
            orderItem = new OrderItem();
            orderItem.setOrderItemId(orderRefund.getOrderItemId());
            orderItem.setPlatformInterventionStatus(ststus);
            orderItemList.add(orderItem);
            // 查询是否有赠品订单项
            giveawayItemList = orderItemService.list(new LambdaQueryWrapper<OrderItem>()
                            .eq(OrderItem::getActivityType,OrderActivityType.GIVEAWAY.value())
                            .eq(OrderItem::getActivityId, orderRefund.getOrderItemId()));
        }
        if (CollUtil.isNotEmpty(giveawayItemList)) {
            for (OrderItem item : giveawayItemList) {
                orderItem = new OrderItem();
                orderItem.setOrderItemId(item.getOrderItemId());
                orderItem.setPlatformInterventionStatus(ststus);
                orderItemList.add(orderItem);
            }
        }

        orderItemService.updateBatchById(orderItemList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelRefundInterventionTimeOut(){
        List<OrderRefundDto> orderRefundList = orderRefundMapper.listCancelRefundInterventionTimeOut(DateUtil.offsetDay(new Date(), -7));
        for (OrderRefundDto orderRefundDto : orderRefundList) {
            orderRefundDto.setPlatformMessage("平台介入超时,系统自动拒绝介入");
            OrderRefund orderRefund = BeanUtil.map(orderRefundDto, OrderRefund.class);
            disagreeIntervention(orderRefund, orderRefundDto.getOrderNumber());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void hanlePlatormIntervertion(OrderRefundInterventionDTO orderRefundInterventionDTO){
        OrderRefund orderRefund = orderRefundMapper.getById(orderRefundInterventionDTO.getRefundId(), null);
        orderRefund.setPlatformMessage(orderRefundInterventionDTO.getPlatformMessage());
        if (Objects.isNull(orderRefund)) {
            // 撤销失败 退款订单不存在
            throw new YamiShopBindException("yami.refund.order.not.exist");
        }
        if (Objects.equals(orderRefund.getReturnMoneySts(), RefundStatusEnum.SUCCEED.value())) {
            throw new YamiShopBindException("yami.refund.succeed.no.dispose.request");
        }
        if (!Objects.equals(orderRefund.getPlatformInterventionStatus(), PlatformInterventionStatus.APPLY.value())) {
            throw new YamiShopBindException("yami.refund.order.status.fail");
        }
        if (!Objects.equals(orderRefund.getPlatformInterventionStatus(), PlatformInterventionStatus.APPLY.value())) {
            throw new YamiShopBindException("yami.platform.involved.status.fail");
        }
        Boolean outTimeCheck = DateUtil.compare(DateUtil.offsetDay(orderRefund.getApplyInterventionTime(),7) , DateUtil.date()) < 0;
        if (outTimeCheck) {
            throw new YamiShopBindException("yami.time.has.passed.no.dispose.involved");
        }
        // 平台拒绝退款介入申请
        if (Objects.equals(orderRefundInterventionDTO.getPlatformInterventionRefundType(), RefundStsType.DISAGREE.value())) {
            orderRefund.setPlatformInterventionStatus(PlatformInterventionStatus.REJECT.value());
            disagreeIntervention(orderRefund, orderRefundInterventionDTO.getOrderNumber());
            logger.info("平台拒绝退款介入申请");
            return;
        }
        // 检查商家

        OrderRefundParam orderRefundParam = BeanUtil.map(orderRefund, OrderRefundParam.class);
        if (Objects.nonNull(orderRefundInterventionDTO.getRefundAmount())) {
            logger.info("平台处理介入退款，设置退款金额refundAmount{}", orderRefundInterventionDTO.getRefundAmount());
            orderRefundParam.setRefundAmount(orderRefundInterventionDTO.getRefundAmount());
        }
        // 处理退款操作
        orderRefundParam.setIsPaltform(true);
        // 获取商家退货地址
        List<RefundAddr> list = refundAddrService.list(new LambdaQueryWrapper<RefundAddr>()
                .eq(RefundAddr::getShopId, orderRefund.getShopId())
                .eq(RefundAddr::getStatus, 1)
                .orderByDesc(RefundAddr::getUpdateTime));
        if (CollUtil.isNotEmpty(list)) {
            orderRefundParam.setRefundAddrId(list.get(0).getRefundAddrId());
        }
        OrderRefundDto orderRefundDto = null;
        if (Objects.equals(orderRefund.getApplyType(), RefundApplyType.REFUND_ONLY.value())) {
            logger.info("平台处理仅退款类型的退款订单介入");
            orderRefundDto = processRefundOrder(orderRefundParam, orderRefund.getShopId());
        }

        if (Objects.equals(orderRefund.getApplyType(), RefundApplyType.RETURN_REFUND.value())) {
            logger.info("平台处理退回退款类型的退款订单介入");
            orderRefundParam.setRefundSts(RefundStsType.AGREE.value());
            orderRefundDto = returnMoney(orderRefundParam, orderRefund.getShopId());
        }


        orderRefundDto.setRefundAmount(orderRefundDto.getRefundAmount());
        int agreeStats = orderRefundMapper.disagreeIntervention(orderRefund.getPlatformMessage(),
                orderRefund.getRefundId(), PlatformInterventionStatus.SUCCESS.value());
        if (agreeStats == 0) {
            throw new YamiShopBindException("yami.order.refund.status.change.do.not.repeat.operation");
        }
        // 更新订单项平台介入状态
        updateItemPlatformIntervertion(orderRefund, orderRefundInterventionDTO.getOrderNumber(), PlatformInterventionStatus.SUCCESS.value());
        // 仅退款，执行退款操作
        submitWxRefund(orderRefundDto);

    }

    /**
     * 关闭订单的退款状态
     * @param orderRefund
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disagreeIntervention(OrderRefund orderRefund, String orderNumber){
        int agreeStats = orderRefundMapper.disagreeIntervention(orderRefund.getPlatformMessage(),
                orderRefund.getRefundId(), PlatformInterventionStatus.REJECT.value());
        if (agreeStats == 0) {
            throw new YamiShopBindException("yami.order.refund.status.change.do.not.repeat.operation");
        }

        // 更新订单
        // 如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
        Integer orderRefundSuccessCount = orderRefundMapper.countReturnProcessingItemByOrderId(orderRefund.getOrderId());
        Order order = new Order();
        order.setOrderId(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
        if (Objects.equals(orderRefundSuccessCount, 0)) {
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
        }
        orderService.updateById(order);
        updateItemPlatformIntervertion(orderRefund, orderNumber, PlatformInterventionStatus.NONE.value());
    }

    @Override
    public void refundOrderStock() {
        int maxsize = 100;
        String keyName = CacheNames.ORDER_REFUND_LOCK_LIST;
        // 获取当前列表的数量，只处理数量内的值，给循环多加一个判断条件，避免死循环
        long size = stockManager.countListByKey(keyName);
        long num = size == 0 ? size : (size / maxsize) + 1;
        // 从列表中或者退款还原库存的订单
        while (num > 0) {
            List<String> list = stockManager.batchListByKey(keyName, maxsize);
            if (CollUtil.isEmpty(list)) {
                break;
            }
            Set<String> recoverySet = this.handleRefundStock(list);
            // 延后处理的数据从列表右边插入 - 重复插入不影响,库存只会处理一次
            if (CollUtil.isNotEmpty(recoverySet)) {
                stockManager.batchPushList(keyName, recoverySet);
            }
            // 从列表左边移除，处理后的数据
            stockManager.trimList(keyName, list.size());
            num--;
        }
    }

    @Override
    public Set<String> handleRefundStock(List<String> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptySet();
        }
        Map<Long, Date> refundMap = new HashMap<>(list.size());
        for (String refundData : list) {
            // 分隔sku退款数据
            String[] skuArray = refundData.split(Constant.UNDERLINE);
            Long refundId = Long.parseLong(skuArray[0]);
            Date time = new Date(Long.parseLong(skuArray[1]));
            refundMap.put(refundId, time);

        }
        // 50s前的时间戳, 等待事务结束后再处理订单(等待获取InnoDB行锁的最大时间默认是50s, 超时事务回滚)
        long innodbLockTimeout = DateUtil.offsetSecond(new Date(), -50).getTime();
        // 回退到列表中的key
        Set<String> recoverySet = new HashSet<>(list.size());
        // 查询退款订单数据
        List<OrderRefundDto> refundOrderList = orderRefundMapper.listOrderRefundByRefundId(new ArrayList<>(refundMap.keySet()));
        Map<Long, OrderRefundDto> orderRefundMap = refundOrderList.stream().collect(Collectors.toMap(OrderRefundDto::getRefundId, Function.identity()));
        Map<String, SkuStockVO> skuStockMap = new HashMap<>();
        List<SkuStockVO> seckillSkuStockList = new ArrayList<>();
        // 确认库存或者回退库存，批量处理，lua可重复执行（幂等）
        for (String refundData : list) {
            String[] skuArray = refundData.split(Constant.UNDERLINE);
            Long refundId = Long.parseLong(skuArray[0]);
            Date time = new Date(Long.parseLong(skuArray[1]));
            OrderRefundDto orderRefundDto = orderRefundMap.get(refundId);
            if (Objects.isNull(orderRefundDto)) {
                recoverySet.add(refundId + Constant.UNDERLINE + time.getTime());
                continue;
            }
            // 退款订单事务未结束,或者处理失败
            if (Objects.isNull(orderRefundDto.getRefundTime())) {
                // 事务未超时,等待下一次定时任务再处理
                if (time.getTime() > innodbLockTimeout) {
                    recoverySet.add(refundId + Constant.UNDERLINE + time.getTime());
                } else {
                    // 已超过锁的处理时间, 则回退锁定的库存到销量
                    this.loadRefundStock(orderRefundDto, skuStockMap, seckillSkuStockList, time, StatusEnum.DISABLE);
                }
                continue;
            }
            // 退款成功
            this.loadRefundStock(orderRefundDto, skuStockMap, seckillSkuStockList, time, StatusEnum.ENABLE);
        }
        // 处理sku库存
        if (CollUtil.isNotEmpty(seckillSkuStockList)) {
            // 秒杀订单
            eventPublisher.publishEvent(new RefundStockSuccessEvent(seckillSkuStockList));
        }
        if (MapUtil.isNotEmpty(skuStockMap)) {
            // 非秒杀订单
            List<SkuStockVO> skuStockList = new ArrayList<>(skuStockMap.values());
            skuStockService.resetStock(skuStockList);
            List<String[]> dataList = new ArrayList<>(skuStockList.size());
            for (SkuStockVO skuStockVO : skuStockList) {
                dataList.add(StockUtil.loadQueryArray(
                   skuStockVO.getSkuId(),
                   skuStockVO.getStock(),
                   skuStockVO.getStockPointId(),
                   skuStockVO.getRefundId(),
                   skuStockVO.getTime().getTime(),
                   skuStockVO.getStatus(),
                   skuStockVO.getDefaultPointId()
                ));
            }
            String result = stockManager.executeLuk(dataList, StockManager.REFUND_STOCK_HANDLE_BYTES);
            log.info("订单退款库存处理： {}", result);
        }
        return recoverySet;
    }

    private void loadRefundStock(OrderRefundDto orderRefundDto, Map<String, SkuStockVO> skuStockMap, List<SkuStockVO> seckillSkuStockList, Date refundTime, StatusEnum statusEnum) {
        for (OrderItem orderItem : orderRefundDto.getOrderItems()) {
            int stock;
            if (Objects.equals(orderRefundDto.getRefundType(), RefundType.SINGLE.value())) {
                // 单项退款
                stock = orderItem.getStatus() == -1 ? orderItem.getProdCount() : orderItem.getStatus();
            } else {
                // 整单退款
                stock = orderItem.getProdCount();
            }
            long stockPoint = orderItem.getStockPointId();
            if (Objects.equals(orderItem.getMold(), ProdMoldEnum.COMBO.value())) {
                stockPoint = Constant.ZERO_LONG;
            }
            if (Objects.equals(orderRefundDto.getOrderType(), OrderType.SECKILL.value())) {
                // TODO stock 秒杀退款
                SkuStockVO skuStockVO = new SkuStockVO(orderItem.getSkuId(), stock, orderItem.getStockPointId(), null);
                skuStockVO.setRefundId(orderRefundDto.getRefundId());
                skuStockVO.setActivityId(orderItem.getActivityId());
                skuStockVO.setTime(refundTime);
                skuStockVO.setUserId(orderRefundDto.getUserId());
                skuStockVO.setStatus(statusEnum.value());
                seckillSkuStockList.add(skuStockVO);
            } else {
                String key = orderRefundDto.getRefundId() + Constant.UNDERLINE + orderItem.getSkuId() + Constant.UNDERLINE + refundTime.getTime();
                SkuStockVO skuStockVO = skuStockMap.get(key);
                if (Objects.isNull(skuStockVO)) {
                    skuStockVO = new SkuStockVO(orderItem.getSkuId(), stock, stockPoint, null);
                    skuStockVO.setRefundId(orderRefundDto.getRefundId());
                    skuStockVO.setTime(refundTime);
                    skuStockVO.setStatus(statusEnum.value());
                    skuStockVO.setShopId(orderItem.getShopId());
                    skuStockVO.setProdId(orderItem.getProdId());
                    skuStockVO.setOrderNumber(orderItem.getOrderNumber());
                    skuStockMap.put(key, skuStockVO);
                    continue;
                }
                skuStockVO.setStock(skuStockVO.getStock() + stock);
            }
        }
    }

    /**
     * 同意退款操作（生成结算记录）
     */
    private void agreeRefund(OrderRefundDto orderRefundDto) {
        Date nowDate = new Date();
        // 查询支付记录
        OrderSettlement orderSettlement = orderSettlementService.getById(orderRefundDto.getSettlementId());
        if (orderSettlement == null) {
            // 没有查询到支付记录，无法申请退款
            throw new YamiShopBindException("yami.not.refunds.requested");
        }
        if (refundOrderSettlementService.count(new LambdaQueryWrapper<RefundOrderSettlement>().eq(RefundOrderSettlement::getRefundSn, orderRefundDto.getRefundSn())) > 0) {
            // 订单正在进行退款结算，请勿重复操作
            throw new YamiShopBindException("yami.refund.progress");
        }

        // 生成退款结算记录
        RefundOrderSettlement refundOrderSettlement = new RefundOrderSettlement();
        refundOrderSettlement.setOrderNumber(orderRefundDto.getOrderNumber());
        refundOrderSettlement.setOrderPayNo(orderRefundDto.getOrderPayNo());
        refundOrderSettlement.setRefundSn(orderRefundDto.getRefundSn());
        refundOrderSettlement.setPayType(orderSettlement.getPayType());
        refundOrderSettlement.setRefundAmount(orderRefundDto.getRefundAmount());
        refundOrderSettlement.setOrderTotalAmount(orderRefundDto.getOrderAmount());
        refundOrderSettlement.setUserId(orderRefundDto.getUserId());
        refundOrderSettlement.setRefundStatus(1);
        refundOrderSettlement.setCreateTime(nowDate);
        refundOrderSettlement.setUpdateTime(nowDate);
        refundOrderSettlementService.save(refundOrderSettlement);

        // 更新退款单信息
        orderRefundDto.setDecisionTime(nowDate);
        orderRefundDto.setUpdateTime(nowDate);


    }

    /**
     * 提交退款请求（向微信发起退款请求）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitWxRefund(OrderRefundDto orderRefundDto) {
        // 判断是否已同意退款
        if (orderRefundDto.getDecisionTime() == null) {
            return;
        }
        OrderSettlement orderSettlement = orderSettlementService.getById(orderRefundDto.getSettlementId());
        RefundInfoDto refundInfo = new RefundInfoDto();
        refundInfo.setRefundSn(orderRefundDto.getRefundSn());
        refundInfo.setBizUserId(orderRefundDto.getShopId());
        refundInfo.setPayNo(orderSettlement.getPayNo());
        refundInfo.setRefundAmount(orderRefundDto.getRefundAmount());
        refundInfo.setRefundOrderNumbers(Collections.singletonList(orderSettlement.getOrderNumber()));
        refundInfo.setReqDate(DateTools.getCurrentDateYYYYMMDD());
        refundInfoService.doRefund(refundInfo);
        orderRefundDto.setStockKeys(refundInfo.getStockKeys());
        payInfoService.markerRefund(orderSettlement.getPayNo());
    }

    @Override
    public double sumRefundSuccessAmountByOrderId(Long orderId) {
        return orderRefundMapper.sumRefundSuccessAmountByOrderId(orderId);
    }

    @Override
    public List<OrderRefund> getProcessingOrderRefundByOrderId(Long orderId) {
        return orderRefundMapper.getProcessingOrderRefundByOrderId(orderId);
    }

    /**
     * 退款成功（更新退款结算记录、更新订单、还原库存）
     */
    private void refundSuccess(Order order, OrderRefundDto orderRefundDto, RefundInfo refundInfo) {
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            order.setStatus(OrderStatus.CLOSE.value());
            order.setCancelTime(new Date());
            order.setUpdateTime(new Date());
            order.setCloseType(OrderCloseType.REFUND.value());
            order.setRefundStatus(RefundStatusEnum.SUCCEED.value());
        } else {
            // 已退款单
            List<OrderRefund> orderRefundList = orderRefundMapper.selectList(new LambdaQueryWrapper<OrderRefund>()
                    .eq(OrderRefund::getOrderId, orderRefundDto.getOrderId())
                    .eq(OrderRefund::getReturnMoneySts, ReturnMoneyStsType.SUCCESS.value())
            );

            // 查看是否已经达到了所有的订单数量，如是则订单关闭
            int totalRefundNum = statisticsTotalRefundNum(orderRefundList, orderRefundDto);
            // 虚拟商品订单：已核销数量也参与商品总数统计
            long virtualWriteNum = 0L;
            if (Objects.equals(1, order.getOrderMold())) {
                virtualWriteNum = orderVirtualInfoService.count(new LambdaQueryWrapper<OrderVirtualInfo>()
                        .eq(OrderVirtualInfo::getOrderNumber, order.getOrderNumber())
                        .eq(OrderVirtualInfo::getIsWriteOff, 1));
            }
            // 整个订单完成退款的时候 - 是否已经达到了所有的订单数量，如是则订单关闭
            if (totalRefundNum + virtualWriteNum >= order.getProductNums()) {
                order.setStatus(OrderStatus.CLOSE.value());
                order.setCancelTime(new Date());
                order.setUpdateTime(new Date());
                order.setCloseType(OrderCloseType.REFUND.value());
                order.setRefundStatus(RefundStatusEnum.SUCCEED.value());
            } else {
                order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
            }

            // 退款成功后，订单没有关闭，且发货订单项 + 退款成功订单项 = 订单项总数量 ，订单状态改为待收货
            if (!Objects.equals(order.getStatus(), OrderStatus.CLOSE.value()) && Objects.equals(order.getStatus(), OrderStatus.PADYED.value())) {
                List<OrderItem> list = orderItemService.list(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
                Integer unRefundCount = 0;
                Integer refundCount = 0;
                for (OrderItem orderItem : list) {
                    boolean isGiveawayProd = Objects.equals(orderItem.getActivityType(),OrderActivityType.GIVEAWAY.value()) && Objects.equals(orderItem.getActivityId(), orderRefundDto.getOrderItemId());
                    if (Objects.equals(orderItem.getOrderItemId(), orderRefundDto.getOrderItemId()) || isGiveawayProd) {
                        refundCount++;
                        continue;
                    }
                    if (Objects.equals(orderItem.getStatus(), 0)) {
                        unRefundCount++;
                    }
                }
                if (orderRefundList.size() + unRefundCount + refundCount >= list.size()) {
                    order.setStatus(OrderStatus.CONSIGNMENT.value());
                    order.setDvyTime(new Date());
                }
                order.setUpdateTime(new Date());
            }
        }
        orderService.updateById(order);

        OrderRefundDto orderRefund = getOrderRefundByRefundSn(orderRefundDto.getRefundSn());
        List<OrderItem> orderItems = orderRefund.getOrderItems();
        List<OrderItem> giveawayList = new ArrayList<>();
        // 发票状态更改
        Long orderInvoiceId = orderInvoiceService.getByorderNumber(order.getOrderNumber());
        if (Objects.nonNull(orderInvoiceId)) {
            OrderInvoice orderInvoice = orderInvoiceService.getById(orderInvoiceId);
            if (Objects.nonNull(orderInvoice)) {
                orderInvoice.setInvoiceState(OrderInvoiceState.FAIL.value());
                orderInvoiceService.updateById(orderInvoice);
            }
        }
        // 更新退款状态
        orderRefundDto.setReturnMoneySts(ReturnMoneyStsType.SUCCESS.value());
        orderRefundDto.setRefundTime(new Date());
        this.updateById(orderRefundDto);
        List<SkuStockVO> skuStockList = new ArrayList<>();
        // 还原库存
        recoveryStock(order, orderRefundDto, orderRefund, orderItems, giveawayList, skuStockList);
        // 退款成功处理
        orderRefundSuccessHandle(order, orderRefundDto, orderItems, giveawayList, skuStockList);
        // 库存还原的退款订单数据
        if (CollUtil.isNotEmpty(skuStockList)) {
            List<String> stockKeys = new ArrayList<>(skuStockList.size());
            for (SkuStockVO value : skuStockList) {
                String key = value.getRefundId() + Constant.UNDERLINE + value.getTime().getTime();
                if (!stockKeys.contains(key)) {
                    stockKeys.add(key);
                }
            }
            refundInfo.setStockKeys(stockKeys);
        } else {
            refundInfo.setStockKeys(Collections.emptyList());
        }
    }

    private int statisticsTotalRefundNum(List<OrderRefund> orderRefundList, OrderRefundDto orderRefundDto) {
        // 获取原本的退货数量，不被之前的处理影响
        OrderRefund orderRefundByRefundSn = orderRefundMapper.selectById(orderRefundDto.getRefundId());
        int totalRefundNum = orderRefundByRefundSn.getGoodsNum();
        orderRefundDto.setGoodsNum(totalRefundNum);
        Set<String> giveawayOrderItemIds = new HashSet<>();

        // 添加当前退款商品的退款赠品订单项id列表
        if (StrUtil.isNotBlank(orderRefundDto.getReturnGiveawayIds())) {
            CollUtil.addAll(giveawayOrderItemIds, orderRefundDto.getReturnGiveawayIds().trim().split(Constant.COMMA));
        }

        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderNumber(orderRefundDto.getOrderNumber(), false);
        List<OrderItem> childComboOrderItems = orderItems.stream().filter(orderItem -> Objects.equals(orderItem.getActivityType(), OrderActivityType.COMBO_PROD.value()) && Objects.equals(orderItem.getActivityId(), orderRefundDto.getOrderItemId())).toList();
        // 添加当前退款商品的退款组合子订单项id列表
        if (CollectionUtil.isNotEmpty(childComboOrderItems)) {
            int count = childComboOrderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            totalRefundNum += count;
        }

        // 添加已成功退款商品的退款赠品订单项id列表
        if (CollUtil.isNotEmpty(orderRefundList)) {
            for (OrderRefund orderRefund : orderRefundList) {
                totalRefundNum += orderRefund.getGoodsNum();
                if (StrUtil.isBlank(orderRefund.getReturnGiveawayIds())) {
                    continue;
                }
                CollUtil.addAll(giveawayOrderItemIds, orderRefund.getReturnGiveawayIds().trim().split(Constant.COMMA));
            }
        }
        if (CollUtil.isEmpty(giveawayOrderItemIds)) {
            return totalRefundNum;
        }
        // 根据退款赠品的订单项id列表，获取订单项信息
        List<OrderItem> list = orderItemService.list(new LambdaQueryWrapper<OrderItem>().in(OrderItem::getOrderItemId, giveawayOrderItemIds));
        if (CollUtil.isEmpty(list)) {
            return totalRefundNum;
        }
        // 统计赠品的退款数量
        totalRefundNum += list.stream().mapToInt(OrderItem::getProdCount).sum();
        return totalRefundNum;
    }

    /**
     * 取消申请超时的订单，无论该超时订单处于任何状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelWhenTimeOut(OrderRefund orderRefund) {
        Date now = new Date();
        orderRefund.setReturnMoneySts(ReturnMoneyStsType.FAIL.value());
        orderRefund.setSellerMsg("申请退款超时");
        orderRefund.setCancelTime(now);
        orderRefund.setUpdateTime(now);

        // 批量修改订单退款状态
        Order order = new Order();
        order.setOrderId(orderRefund.getOrderId());
        Long orderRefundSuccessCount = orderRefundMapper.selectCount(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderRefund.getOrderId())
                .eq(OrderRefund::getReturnMoneySts, ReturnMoneyStsType.SUCCESS.value()));
        Order orderDb = orderService.getById(orderRefund.getOrderId());
        // 对退款金额发放失败的订单进行处理
        shopWalletService.handleRefundError(orderRefund,orderDb.getPaySysType());
        // 如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
        if (orderRefundSuccessCount > 0) {
            order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
        } else {
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
        }
        updateById(orderRefund);
        orderService.updateById(order);
    }

    @Override
    public boolean checkRefundDate(Order order) {
        // 判断是否超过支持的退款天数
        if (Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value())) {
            long finallyTime = order.getFinallyTime().getTime();
            long currentTime = System.currentTimeMillis();
            int miniTime = Constant.MAX_FINALLY_REFUND_TIME * 24 * 60 * 60 * 1000;
            return currentTime - finallyTime <= miniTime;
        }
        return true;
    }

    @Override
    public double sumRefundSuccessPlatformAmountByOrderId(Long orderId) {
        return orderRefundMapper.sumRefundSuccessPlatformAmountByOrderId(orderId);
    }

    @Override
    public UserManagerParam getRefundDataByUserId(UserManagerParam param) {
        String userId = param.getUserId();
        // 售后金额，退款金额
        Double amount = orderRefundMapper.countRefundAmountByUserId(userId);
        param.setAfterSaleAmount(Objects.nonNull(amount) ? amount : 0.0);
        // 售后次数，退款次数
        param.setAfterSaleTimes(orderRefundMapper.countRefundNumByUserId(userId));
        return param;
    }

    @Override
    public void updateByRefundSn(OrderRefund orderRefund) {
        orderRefundMapper.updateByRefundSn(orderRefund);
    }

    @Override
    public Boolean getIsLastRefund(String refundSn, Long shopId) {
        OrderRefundDto orderRefundDto = orderRefundMapper.getOrderRefundByRefundSn(refundSn);
        if (Objects.isNull(shopId)) {
             shopId = orderRefundDto.getShopId();
        }
        if (Objects.isNull(orderRefundDto)) {
            //退款单不存在
            throw new YamiShopBindException("yami.order.refund.exist");
        }
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            //整单退款
            return false;
        }
        if (Objects.equals(orderRefundDto.getApplyType(), RefundApplyType.RETURN_REFUND.value())) {
            //退货退款
            return false;
        }
        Order order = orderService.getOrderByOrderNumberAndShopId(orderRefundDto.getOrderNumber(), shopId, true);
        if (!Objects.equals(order.getStatus(), OrderStatus.PADYED.value())) {
            //非待发货
            return false;
        }
        //退款成功总数以及在退款回调中的订单
        long refundCount = count(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderRefundDto.getOrderId())
                .in(OrderRefund::getReturnMoneySts, ReturnMoneyStsType.SUCCESS.value(), ReturnMoneyStsType.PROCESSING.value()));
        //所有订单项总数
        long orderItemCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, order.getOrderNumber())
                .ne(OrderItem::getActivityType,OrderActivityType.COMBO_PROD.value())
                .ne(OrderItem::getActivityType,OrderActivityType.GIVEAWAY.value()));
        return Objects.equals(refundCount, orderItemCount - 1);
    }

    @Override
    public List<OrderRefundDto> listRefundInfoByRefundSnList(List<String> refundSnList) {
        if (CollUtil.isEmpty(refundSnList)) {
            return new ArrayList<>();
        }
        List<OrderRefundDto> orderRefundList = orderRefundMapper.listOrderRefundByRefundSn(refundSnList);
        orderRefundList.forEach(orderRefundDto -> getRefundTypeByOrderItem(orderRefundDto, 1));
        return orderRefundList;
    }

    @Override
    public List<OrderRefundDto> listShouldRefundRequest() {
        return orderRefundMapper.listShouldRefundRequest();
    }

    private void checkLastRefund(OrderRefundDto orderRefundDto) {
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            return;
        }
        Order order = orderService.getOrderByOrderNumber(orderRefundDto.getOrderNumber());
        if (!Objects.equals(order.getStatus(), OrderStatus.PADYED.value())) {
            return;
        }
        //所有订单项总数
        long orderItemCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, order.getOrderNumber())
                .ne(OrderItem::getActivityType,OrderActivityType.COMBO_PROD.value())
                .ne(OrderItem::getActivityType,OrderActivityType.GIVEAWAY.value()));
        //退款成功总数以及在退款回调中的订单
        long refundCount = count(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderRefundDto.getOrderId())
                .in(OrderRefund::getReturnMoneySts, ReturnMoneyStsType.SUCCESS.value(), ReturnMoneyStsType.PROCESSING.value()));
        if (Objects.equals(refundCount, orderItemCount - 1)) {
            //最后一单
            if (order.getPlatformFreeFreightAmount() == 0.0 && order.getFreightAmount() > 0.0) {
                orderRefundDto.setRefundAmount(Arith.add(order.getFreightAmount(), orderRefundDto.getRefundAmount()));
            }
            // 平台退款金额需要加上平台补贴的运费金额
            orderRefundDto.setPlatformRefundAmount(Arith.add(orderRefundDto.getPlatformRefundAmount(),order.getPlatformFreeFreightAmount()));
            Double shareReduce = orderRefundDto.getOrderItems().get(0).getShareReduce();
            // 最后一单时需要优惠金额需要加上平台补贴的运费金额
            orderRefundDto.getOrderItems().get(0).setShareReduce(Arith.add(shareReduce,order.getPlatformFreeFreightAmount()));
        }
    }

    private void recoveryStock(Order order, OrderRefundDto orderRefundDto, OrderRefundDto orderRefund,
                                    List<OrderItem> orderItems, List<OrderItem> giveawayList, List<SkuStockVO> skuStockList) {
        // 放入赠品一并还原赠品库存
        List<OrderItem> comboList = new ArrayList<>();
        for (OrderItem orderItem : orderItems) {
            if (CollectionUtils.isNotEmpty(orderItem.getGiveawayList())) {
                giveawayList.addAll(orderItem.getGiveawayList());
            }
            if (CollUtil.isNotEmpty(orderItem.getComboList())) {
                comboList.addAll(orderItem.getComboList());
            }
        }
        orderItems.addAll(comboList);
        if (CollectionUtils.isNotEmpty(giveawayList)) {
            orderItems.addAll(giveawayList);
        }
        List<Long> deleteIds = Collections.emptyList();
        if (!Objects.equals(order.getOrderType(), OrderType.SECKILL.value())) {
            List<Long> skuIds = orderItems.stream().map(OrderItem::getSkuId).collect(Collectors.toList());
            // 已删除的sku列表
            List<Sku> skuDeleteList = skuService.list(new LambdaQueryWrapper<Sku>().in(Sku::getSkuId, skuIds).eq(Sku::getIsDelete, 1));
            deleteIds = skuDeleteList.stream().map(Sku::getSkuId).collect(Collectors.toList());
        }
        Map<Long, SkuStockVO> skuStockMap = new HashMap<>(orderItems.size());
        for (OrderItem orderItem : orderItems) {
            if (Objects.equals(order.getOrderType(), OrderType.SECKILL.value())) {
                // 退货退款或待发货仅退款
                boolean canReturnStock = Objects.equals(orderRefundDto.getApplyType(), 2) || (Objects.equals(orderRefundDto.getApplyType(), 1) && orderItem.getStatus() != 0);
                if (canReturnStock) {
                    // 秒杀订单，归还待发货库存到秒杀表
                    Integer prodCount = Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value()) ? orderItem.getProdCount() : orderRefund.getGoodsNum();
                    applicationContext.publishEvent(new UpdateSeckillOrderSkuInfoEvent(
                            orderRefundDto.getRefundId(), orderItem.getActivityId(), orderItem.getSkuId(),
                            orderItem.getStockPointId(), prodCount, orderRefundDto.getRefundTime())
                    );
                    SkuStockVO skuStockVO = new SkuStockVO();
                    skuStockVO.setRefundId(orderRefund.getRefundId());
                    skuStockVO.setTime(orderRefundDto.getRefundTime());
                    skuStockList.add(skuStockVO);
                }
            }
            // 其他订单，归还待发货库存到商品表
            else {
                // 未全部发货，且sku没有删除的商品恢复库存，此时不需要核销的也会在这里进行退库存
                if (orderItem.getStatus() != 0 && !deleteIds.contains(orderItem.getSkuId())) {
                    SkuStockVO skuStockVO = loadRefundStock(orderRefundDto, orderItem, skuStockMap);
                    int stock = orderItem.getStatus() == -1 ? orderItem.getProdCount() : orderItem.getStatus();
                    skuStockVO.setStock(skuStockVO.getStock() + stock);
                }
                // 虚拟商品有核销时的退库存判断,没有核销完成时退库存
                if(Objects.equals(order.getOrderMold(),1) && Objects.equals(order.getWriteOffStatus(),0) && !Objects.equals(order.getWriteOffNum(), 0)) {
                    SkuStockVO skuStockVO = loadRefundStock(orderRefundDto, orderItem, skuStockMap);
                    skuStockVO.setStock(skuStockVO.getStock() + orderItem.getProdCount());
                }
            }
        }

        // =================== 还原库存 =========================
        // 库存没有直接回退到可售卖库存，而是增加到锁定库存，防止事务回滚导致超卖，真正的处理在事务结束后：OrderRefundService.refundOrderStock()
        // 普通订单 - 还原库存
        if (MapUtil.isNotEmpty(skuStockMap)) {
            skuStockList.addAll(skuStockMap.values());
            skuStockService.orderRefundRecoveryStock(skuStockList);
        }
    }

    private static SkuStockVO loadRefundStock(OrderRefundDto orderRefundDto, OrderItem orderItem, Map<Long, SkuStockVO> skuStockMap) {
        SkuStockVO skuStockVO = skuStockMap.get(orderItem.getSkuId());
        if (Objects.isNull(skuStockVO)) {
            long stockPointId = orderItem.getStockPointId();
            if (Objects.equals(orderItem.getMold(), ProdMoldEnum.COMBO.value())) {
                stockPointId = Constant.ZERO_LONG;
            }
            skuStockVO = new SkuStockVO(orderItem.getSkuId(), stockPointId);
            skuStockVO.setStock(0);
            skuStockVO.setProdId(orderItem.getProdId());
            skuStockVO.setTime(orderRefundDto.getRefundTime());
            skuStockVO.setRefundId(orderRefundDto.getRefundId());
            skuStockVO.setShopId(orderRefundDto.getShopId());
            skuStockMap.put(orderItem.getSkuId(), skuStockVO);
        }
        return skuStockVO;
    }

    private void orderRefundSuccessHandle(Order order, OrderRefundDto orderRefundDto, List<OrderItem> orderItems, List<OrderItem> giveawayList,
                                          List<SkuStockVO> skuStockList) {
        if (Objects.equals(order.getOrderType(), OrderType.SECKILL.value())) {
            return;
        }
        if (CollectionUtils.isNotEmpty(giveawayList)) {
            orderRefundDto.getOrderItems().addAll(giveawayList);
        }
        Map<Long, Long> skuMap = this.handleRefundStockPointData(orderRefundDto, skuStockList);
        // 退款时分销需要计算 orderItems
        order.setOrderItems(orderItems);
        // 生成入库明细
        stockBillLogService.generateStockLogOfRefundOrder(orderRefundDto, StockBillType.RETURN_STORAGE.value(), StockType.WAREHOUSING.value());
        // (非秒杀订单) 如果有tz_stock_point_sku有数据变动，需要清除sku缓存
        skuService.batchRemoveSkuStockCache(skuMap);

//        // 更新es中的商品库存
//        try {
//            eventPublisher.publishEvent(new EsProductUpdateEvent(null, new ArrayList<>(prodIds), EsOperationType.UPDATE_SOLD_NUM_BATCH));
//        } catch (Exception e) {
//            log.error("订单退款-更新es商品库存失败，错误为：", e);
//        }
    }

    private Map<Long, Long> handleRefundStockPointData(OrderRefundDto orderRefundDto, List<SkuStockVO> skuStockList) {
        if (CollUtil.isEmpty(skuStockList)) {
            return Collections.emptyMap();
        }
        List<OrderItem> orderItems = orderRefundDto.getOrderItems();
        Map<Long, Long> skuMap = skuStockService.resetStock(skuStockList);
        Map<String, SkuStockVO> skuStockMap = new HashMap<>(skuStockList.size());

        List<StockPointSkuVO> stockPointSkuVOList = new ArrayList<>(skuStockList.size());
        for (SkuStockVO skuStockVO : skuStockList) {
            if (skuStockVO.getStockPointId() == 0) {
                continue;
            }
            long stockPointId = Objects.nonNull(skuStockVO.getDefaultPointId()) ? skuStockVO.getDefaultPointId() : skuStockVO.getStockPointId();
            stockPointSkuVOList.add(new StockPointSkuVO(skuStockVO.getSkuId(), stockPointId));
        }
        Map<String, SkuStockVO> skuStockPointMap = skuStockService.mapSkuPointStockByStockPoints(stockPointSkuVOList);
        for (SkuStockVO skuStockVO : skuStockList) {
            long stockPointId = Objects.nonNull(skuStockVO.getDefaultPointId()) ? skuStockVO.getDefaultPointId() : skuStockVO.getStockPointId();
            // 非组合商品，设置剩余库存数量
            SkuStockVO skuStock = skuStockPointMap.get(skuStockVO.getSkuId() + Constant.UNDERLINE + stockPointId);
            if (stockPointId > 0 && Objects.nonNull(skuStock)) {
                skuStockVO.setAfterStock(skuStock.getStock() + skuStockVO.getStock());
            }
            String refundSkuKey = skuStockVO.getRefundId() + Constant.UNDERLINE + skuStockVO.getSkuId();
            if (!skuStockMap.containsKey(refundSkuKey)) {
                skuStockMap.put(refundSkuKey, skuStockVO);
            }
        }
        for (OrderItem orderItem : orderItems) {
            orderItem.setReturnMoneySts(ReturnMoneyStsType.SUCCESS.value());
            SkuStockVO skuStockVO = skuStockMap.get(orderRefundDto.getRefundId() + Constant.UNDERLINE + orderItem.getSkuId());
            if (Objects.isNull(skuStockVO)) {
                continue;
            }
            orderItem.setAfterStock(skuStockVO.getAfterStock());
            if (Objects.nonNull(skuStockVO.getDefaultPointId())) {
                log.info("订单退款-区域仓库删除，替换为默认仓库：refundId:{}, skuId: {}", orderRefundDto.getRefundId(), orderItem.getSkuId());
                orderItem.setStockPointId(skuStockVO.getDefaultPointId());
                orderItem.setStockPointType(StockPointType.WAREHOUSE.getValue());
            }
        }
        return skuMap;
    }
}
